package org.lep.leetcode.uniquebinarysearchtree;

/**
 * Source : https://oj.leetcode.com/problems/unique-binary-search-trees/
 *
 * Created by lverpeng on 2017/8/8.
 *
 * Given n, how many structurally unique BST's (binary search trees) that store values 1...n?
 *
 * For example,
 * Given n = 3, there are a total of 5 unique BST's.
 *
 *    1         3     3      2      1
 *    \       /     /      / \      \
 *    3     2     1      1   3      2
 *    /     /       \                 \
 *    2     1         2                 3
 *
 *
 */
public class UniqueBinarySearchTree {


    /**
     * 求出给定n的所有唯一的二叉搜索树
     * 二叉搜索树：
     * 如果左子树不为空，则左子树的节点值要小于根节点的值，如果右节点不为空，则右子树节点的值大于根节点的值
     *
     * 找规律
     * 设n的唯一二叉搜索树个数为f(n)
     * n = 0, f(0) = 1
     * n = 1, f(1) = 1
     * n = 2, f(2) = 2
     * n = 3, f(3) = 5
     * .....
     *
     * 讨论n = 3的情况
     * 当根节点为1，左子树必须为空，则总数取决于右子树的个数，f(0)*f(n-1)=f(0)*f(2)=2
     * 当根节点为2，左子树为1，右子树为3，在总数为f(1)*(n-2)=f(1)*(1)=1
     * 当根节点为3，左子树为空，可能有f(0)*f(2)，左子树为1，可能有f(1)*f(1)，左子树为2，可能有f(2)*f(0)=2，总共有2+1+2=5
     *
     * 所以：
     * f(0) = 1
     * f(n) = f(0)*f(n-1) + f(1)f(n-2) + f(2)*f(n-3) + ... + f(n-3)f(2) + f(n-2)*f(1) + f(n-1)f(0);
     *
     * 注意：因为要计算f(n)，所以数组长度应该为n+1，因为要保存0-n之间的结果
     *
     *
     * @param n
     * @return
     */
    public int uniqueTreeCount (int n) {
        if (n == 0) {
            return 1;
        }
        int[] dp = new int[n+1];
        dp[0] = 1;
        for (int i = 1; i <= n; i++) {
            for (int j = 0; j < i; j++) {
                dp[i] += dp[j] * dp[i-j-1];
            }
        }

        return dp[n];
    }

    public static void main(String[] args) {
        UniqueBinarySearchTree uniqueBinarySearchTree = new UniqueBinarySearchTree();
        System.out.println(uniqueBinarySearchTree.uniqueTreeCount(0));
        System.out.println(uniqueBinarySearchTree.uniqueTreeCount(1));
        System.out.println(uniqueBinarySearchTree.uniqueTreeCount(2));
        System.out.println(uniqueBinarySearchTree.uniqueTreeCount(3));
    }

}
